home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / rpg / crossfir.92 / crossfir / crossfire-0.92.5 / server / ericserver.c < prev    next >
C/C++ Source or Header  |  1996-07-24  |  32KB  |  1,293 lines

  1. /*
  2.  * This file implements all of the goo on the server side for handling 
  3.  * clients.  It's got a bunch of global variables for keeping track of 
  4.  * each of the clients. 
  5.  *
  6.  * SWH sends a message, protecting against certain exceptions being thrown.
  7.  *
  8.  * InitConnection initializes the connection with the client, and sends
  9.  * the server's protocol version (the client sends one of these too)
  10.  *
  11.  * PlayerCmd executes commands from the player 
  12.  *
  13.  * VersionCmd checks the version number of the client
  14.  *
  15.  * AddMeCmd adds the player to the game. 
  16.  *
  17.  * KeyConversion/KeyPress/KeyRelease are deprecated.
  18.  *
  19.  * Examine,Apply,Move Cmd handle those things
  20.  *
  21.  * dropconnection destroys the connection from the client.
  22.  *
  23.  * init_ericserver reads in all of the bitmap information, and initializes
  24.  * lots of spoo.
  25.  *
  26.  * CmdMapping is the dispatch table for the server, used in HandleClient,
  27.  * which gets called when the client has input.
  28.  *
  29.  * esrv_remove_player removes a player (called from xfire sources)
  30.  *
  31.  * esrv_drawinfo sends drawing info to the client
  32.  *
  33.  * send_query asks the client to query the user
  34.  *
  35.  * esrv_print_msg draws a normal message on the client
  36.  *
  37.  * esrv_write_ch is deprecated
  38.  *
  39.  * esrv_foo and esrv_bar are for debugging and just ship across server
  40.  * messages
  41.  *
  42.  * esrv_update_stats sends a statistics update.
  43.  *
  44.  * blah blah blah more esrv_* commands
  45.  *
  46.  * esrv_send_face sends a face to a client if they are in pixmap mode
  47.  * nothing gets sent in bitmap mode. 
  48.  *
  49.  * esrv_map_new starts updating the map
  50.  *
  51.  * esrv_map_clearcell clears a map cell
  52.  *
  53.  * esrv_map_setbelow allows filling in all of the faces for the map.
  54.  * if a face has not already been sent to the client, it is sent now.
  55.  *
  56.  * mapcellchanged, compactlayer, compactstack, perform the map compressing
  57.  * operations
  58.  *
  59.  * esrv_map_doneredraw finishes the map update, and ships across the
  60.  * map updates. 
  61.  *
  62.  * esrv_map_scroll tells the client to scroll the map, and does similarily
  63.  * for the locally cached copy.
  64.  */
  65. #undef StupidSunHeaders
  66. #include <global.h>
  67. #include <sproto.h>
  68. #undef HANDLE
  69.  
  70. #if ERIC_SERVER
  71.  
  72. #include <tcplib.h>
  73. #include <xmalloc.h>
  74. #include <libc.h>
  75. #include <arglist.h>
  76. #include <xfile.h>
  77. /*#include <chain-hash.h>*/
  78. #include <newclient.h>
  79.  
  80. extern FILE *logfile;
  81. extern int color_pix;
  82.  
  83. #define MAX_BUF 256
  84. #define ESRV_VERSION 1002
  85. #endif    /* ERICSERVER */
  86.  
  87. #define EPORT 17399 /* (ESRV)_26 = 82935 % 32768 = 17399 */
  88. int eport = EPORT;
  89.  
  90. #if ERICSERVER
  91.  
  92. /* List of integer defined commands */
  93. #define STRINGCOMMAND 0
  94.  
  95. enum CState { CState_Init,CState_CanAdd,CState_Dead };
  96. #define MAXMAPCELLFACES 50
  97. /* Absolute MAX = 16383 given current map compaction algorithm */
  98. #define MAXFACENUM 5000 
  99.  
  100. struct MapCell {
  101.   short faces[MAXMAPCELLFACES];
  102.   int count;
  103. };
  104.  
  105. struct Map {
  106.   struct MapCell cells[11][11];
  107. };
  108.  
  109. struct statsinfo {
  110. /*
  111.   long hp,maxhp,sp,maxsp,str,Int,wis,dex,con,cha,exp,level,wc,ac,dam;
  112.   long armour,speed,food,weapon_sp;
  113. */
  114.   char *range,*title;
  115. };
  116.  
  117. enum FaceSendMode { Send_Face_Pixmap, Send_Face_Bitmap, Send_Face_None };
  118.  
  119. typedef struct __ClientInfo {
  120.   enum CState state;
  121.   long client_id;
  122.   int sentscroll; /* have we sent a scroll for the map since the last
  123.              map update? */
  124.   struct Map lastmap;
  125.   char faces_sent[MAXFACENUM];
  126.   enum FaceSendMode facesendmode;
  127. /*  HashTable ks2kc,kc2ks;*/
  128.   struct statsinfo stats;
  129. } ClientInfo;
  130.  
  131. typedef struct __FaceInfo {
  132.   char *name;
  133.   char *data;
  134.   char bitmapdata[3*24];
  135.   long datalen;
  136. } FaceInfo;
  137.  
  138. /*************************
  139.  * Globals for this file *
  140.  *************************/
  141.  
  142. static ClientInfo *cinfo;
  143. static TcpSocket *conns;
  144. static int nconns;
  145. static long totalclients = 0;
  146. static FaceInfo faces[MAXFACENUM];
  147.  
  148. /* Send With Handling */
  149. static void SWH(int cnum,ArgList msg)
  150. {
  151.   if (cinfo[cnum].state == CState_Dead)
  152.     return;
  153.   WITH_HANDLING {
  154.     ArgList_send(conns[cnum],msg);
  155.   } HANDLE {
  156.     BEGIN_MATCH;
  157.     XMATCH(tcplib,WriteFailed) {
  158.       cinfo[cnum].state = CState_Dead;
  159.     } END_MATCH;
  160.   } END_HANDLING;
  161. }
  162.  
  163. static void InitConnection(int cnum)
  164. {
  165.   ArgList msg;
  166.  
  167.   msg = ArgList_create();
  168.   ArgList_addLong(msg,STRINGCOMMAND);
  169.   ArgList_addString(msg,"version");
  170.   ArgList_addLong(msg,ESRV_VERSION);
  171.   SWH(cnum,msg);
  172.   ArgList_destroy(msg);
  173.   cinfo[cnum].state = CState_Init;
  174.   cinfo[cnum].facesendmode = Send_Face_Pixmap;
  175.   totalclients++;
  176.   cinfo[cnum].client_id = totalclients;
  177.   memset(&cinfo[cnum].lastmap,0,sizeof(struct Map));
  178.   memset(&cinfo[cnum].faces_sent,0,sizeof(cinfo[cnum].faces_sent));
  179.   memset(&cinfo[cnum].stats,0,sizeof(struct statsinfo));
  180. #if 0
  181.   cinfo[cnum].ks2kc = CreateHashTable(-2000,NULL);
  182.   cinfo[cnum].kc2ks = CreateHashTable(-2000,NULL);
  183. #endif
  184.   cinfo[cnum].state = CState_CanAdd;
  185. }
  186.  
  187. static void PlayerCmd(ArgList msg, int cnum)
  188. {
  189.     int count = ArgList_getLong(msg,2);
  190.     char *buf = ArgList_getString(msg,3);
  191.     object *pl=esrv_getopfromcid(cinfo[cnum].client_id);
  192.  
  193.     if (count) {
  194.     pl->contr->count=count;
  195.     pl->contr->count_left=0;
  196.     }
  197.     /* The following should never happen with a proper or honest client.
  198.      * Therefore, the error message doesn't have to be too clear - if 
  199.      * someone is playing with a hacked/non working client, this gives them
  200.      * an idea of the problem, but they deserve what they get
  201.      */
  202.     if (pl->contr->state!=ST_PLAYING) {
  203.       new_draw_info_format(NDI_UNIQUE, 0,pl,
  204.     "You can not issue commands - state is not ST_PLAYING (%s)", buf);
  205.       return;
  206.     }
  207.     pl->contr->idle=0;
  208.     /* Something better needs to be done.  Ideally, we shouldn't read the
  209.      * data from the socket unless we are sure the client has some to
  210.      * execute it.
  211.      */
  212.     if (pl->speed_left<-1.0) {
  213.     LOG(llevError,"Player has negative time - shouldn't do command.\n");
  214.     }
  215.     /* In c_new.c */
  216.     execute_newserver_command(pl, buf);
  217.     /* Perhaps something better should be done with a left over count.
  218.      * Cleaning up the input should probably be done first - all actions
  219.      * for the command that issued the count should be done before any other
  220.      * commands.
  221.      */
  222.  
  223.     pl->contr->count_left=0;
  224.     pl->contr->count=0;
  225.  
  226.     /* We really should check how much speed the player has left, and
  227.      * start doing something appropriate (like not executing the commands,
  228.      * or stop reading from the socket.
  229.      */
  230. }
  231.  
  232.  
  233. static void ReplyCmd(ArgList msg, int cnum)
  234. {
  235.     char *buf = ArgList_getString(msg,2);
  236.     object *pl=esrv_getopfromcid(cinfo[cnum].client_id);
  237.  
  238.  
  239.     LOG(llevDebug,"In ReplyCmd: got reply '%s'\n", buf);
  240.  
  241.     /* This is to synthesize how the data would be stored if it
  242.      * was normally entered.  A bit of a hack, and should be cleaned up
  243.      * once all the X11 code is removed from the server.
  244.      *
  245.      * We pass 13 to many of the functions because this way they
  246.      * think it was the carriage return that was entered, and the
  247.      * function then does not try to do additional input.
  248.      */
  249.     sprintf(pl->contr->write_buf,":%s", buf);
  250.     pl->contr->writing = strlen(pl->contr->write_buf);
  251.  
  252.     switch (pl->contr->state) {
  253.     case ST_PLAYING:
  254.         LOG(llevError,"Got reply message with ST_PLAYING input state\n");
  255.         break;
  256.  
  257.     case ST_PLAY_AGAIN:
  258.         /* We can check this for return value (2==quit).  Maybe we
  259.          * should, and do something appropriate?
  260.          */
  261.         receive_play_again(pl, buf[0]);
  262.         break;
  263.  
  264.     case ST_ROLL_STAT:
  265.         key_roll_stat(pl,buf[0]);
  266.         break;
  267.  
  268.     case ST_CHANGE_CLASS:
  269.         key_change_class(pl, buf[0]);
  270.         break;
  271.  
  272.     case ST_CONFIRM_QUIT:
  273.         key_confirm_quit(pl, buf[0]);
  274.         break;
  275.  
  276.     case ST_CONFIGURE:
  277.         LOG(llevError,"In client input handling, but into configure state\n");
  278.         pl->contr->state = ST_PLAYING;
  279.         break;
  280.  
  281.     case ST_GET_NAME:
  282.         receive_player_name(pl,13);
  283.         break;
  284.  
  285.     case ST_GET_PASSWORD:
  286.     case ST_CONFIRM_PASSWORD:
  287.         receive_player_password(pl,13);
  288.         break;
  289.  
  290.     /* Pausing should really be done by the client, not the server.
  291.      * but this is easy to handle here.
  292.      */
  293.     case ST_MENU_MORE:
  294.         shop_listing_more(pl);
  295.         break;
  296.  
  297. #ifdef SIMPLE_PARTY_SYSTEM
  298.     case ST_GET_PARTY_PASSWORD:        /* Get password for party */
  299.     receive_party_password(pl,13);
  300.         break;
  301. #endif /* SIMPLE_PARTY_SYSTEM */
  302.  
  303.     default:
  304.         LOG(llevError,"Unknown input state: %d\n", pl->contr->state);
  305.     }
  306. }
  307.  
  308. static int getcnum(long client_id) 
  309. {
  310.   int i;
  311.  
  312.   for(i=1;i<nconns;i++)
  313.     if (cinfo[i].client_id == client_id)
  314.       return i;
  315.   
  316.   return -1;
  317. }
  318.  
  319. static void VersionCmd(ArgList msg,int cnum)
  320. {
  321.   if (ESRV_VERSION != ArgList_getLong(msg,2)) {
  322.     printf("Server, Client have different versions (%d,%ld)\n",
  323.        ESRV_VERSION,ArgList_getLong(msg,2));
  324.     cinfo[cnum].state = CState_Dead;
  325.   }
  326. }
  327.  
  328. static void KeyConversionCmd(ArgList msg,int cnum)
  329. {
  330.   long i,max;
  331.   long ks,kc;
  332.  
  333.   max = ArgList_getLong(msg,2);
  334.   for(i=3;i<3+max;i+=2) {
  335.     ks = ArgList_getLong(msg,i);
  336.     kc = ArgList_getLong(msg,i+1);
  337. #if 0
  338.     HashOverwrite(cinfo[cnum].ks2kc,&ks,sizeof(long),&kc,sizeof(long));
  339. /*    HashOverwrite(cinfo[cnum].kc2ks,&kc,sizeof(long),&ks,sizeof(long));*/
  340. #endif
  341.   }
  342.   cinfo[cnum].state = CState_CanAdd;
  343. }
  344.  
  345. int add_player();
  346. static void AddMeCmd(ArgList msg,int cnum)
  347. {
  348.   int cpix = color_pix;
  349.   ArgList omsg;
  350.  
  351.   omsg = ArgList_create();
  352.   ArgList_addLong(omsg,STRINGCOMMAND);
  353.   color_pix = 1;
  354.   if (cinfo[cnum].state != CState_CanAdd ||
  355.       add_player("nowhere.bad.don't.use.this",
  356.          "someone",NULL,cinfo[cnum].client_id)) {
  357.     ArgList_addString(omsg,"addme_failed");
  358.   } else {
  359.     ArgList_addString(omsg,"addme_success");
  360.   }
  361.   SWH(cnum,omsg);
  362.   ArgList_destroy(omsg);
  363.   color_pix = cpix;
  364. }
  365.  
  366.  
  367. static void KeyPressCmd(ArgList msg,int cnum)
  368. {
  369.   unsigned int keycode;
  370.   unsigned long keysym;
  371.   char key;
  372.  
  373.   keycode = ArgList_getLong(msg,2);
  374.   keysym = ArgList_getLong(msg,3);
  375.   key = ArgList_getLong(msg,4);
  376.   handle_keypress(esrv_getopfromcid(cinfo[cnum].client_id),
  377.           keycode,keysym,key);
  378. }
  379.  
  380.  
  381. static void KeyReleaseCmd(ArgList msg,int cnum)
  382. {
  383.   unsigned int keycode;
  384.   unsigned long keysym;
  385.   char key;
  386.  
  387.   keycode = ArgList_getLong(msg,2);
  388.   keysym = ArgList_getLong(msg,3);
  389.   key = ArgList_getLong(msg,4);
  390.   handle_keyrelease(esrv_getopfromcid(cinfo[cnum].client_id),
  391.             keycode,keysym);
  392. }
  393.  
  394. static void ExamineCmd(ArgList msg,int cnum)
  395. {
  396.   long tag = ArgList_getLong(msg, 2);
  397.  
  398.   esrv_examine_object(esrv_getopfromcid(cinfo[cnum].client_id), tag);
  399. }
  400.  
  401. static void ApplyCmd(ArgList msg,int cnum)
  402. {
  403.   long tag = ArgList_getLong(msg, 2);
  404.  
  405.   esrv_apply_object(esrv_getopfromcid(cinfo[cnum].client_id), tag);
  406. }
  407.  
  408. static void MoveCmd(ArgList msg,int cnum)
  409. {
  410.   long to   = ArgList_getLong(msg, 2);
  411.   long tag  = ArgList_getLong(msg, 3);
  412.   long nrof = ArgList_getLong(msg, 4);
  413.   printf ("Move item %ld (nrof=%ld) to %ld.\n", tag, nrof, to);
  414.   esrv_move_object(esrv_getopfromcid(cinfo[cnum].client_id), to, tag, nrof);
  415. }
  416.  
  417.  
  418.  
  419.  
  420. static void readbufline(char *buf,int size,FILE *in)
  421. {
  422.   buf[0] = '\0';
  423.   fgets(buf,size,in);
  424.   buf[size-1] = '\0';
  425.   if (buf[0] == '\0')
  426.     return;
  427.   if (buf[strlen(buf)-1] != '\n') {
  428.     fprintf(stderr,"whoa, line '%s' not newline terminated??\n",buf);
  429.     abort();
  430.   }
  431. }
  432.  
  433. static void dropconnection(int which)
  434. {
  435.   int j;
  436.  
  437.   CloseConnection(conns[which]);
  438.   if (cinfo[which].stats.range)
  439.     free(cinfo[which].stats.range);
  440.   if (cinfo[which].stats.title)
  441.     free(cinfo[which].stats.title);
  442. #if 0
  443.   DestroyHashTable(cinfo[which].ks2kc,NULL);
  444.   DestroyHashTable(cinfo[which].kc2ks,NULL);
  445. #endif
  446.   nconns--;
  447.   for(j=which;j<nconns;j++) {
  448.     conns[j] = conns[j+1];
  449.     cinfo[j] = cinfo[j+1];
  450.   }
  451. }
  452.  
  453.  
  454. #endif /* if ericserver */
  455.  
  456. long esrv_ks2kc(long client_id,long keysym)
  457. {
  458. #if ERICSERVER
  459.   int cnum;
  460.   if ((cnum = getcnum(client_id))<0) {
  461.     fprintf(logfile,"client %ld is gone.\n",client_id);
  462.     return 0;
  463.   }
  464. #if 0
  465.   return *(long *)HashLookup(cinfo[cnum].ks2kc,&keysym,sizeof(long));
  466. #endif
  467. #endif
  468.   return 0;
  469. }
  470.  
  471.  
  472. void esrv_send_face(long client_id,short face_num);
  473. void init_ericserver()
  474. {
  475. #if ERICSERVER
  476.   char filename[400];
  477.   char buf[500];
  478.   char *databuf,*cur,*end;
  479.   FILE *infile;
  480.   int num,len,comp;
  481.  
  482.   LOG(llevDebug,"Initialize new client/server data\n");
  483.   nconns = 1;
  484.   conns = xmalloc(sizeof(TcpSocket));
  485.   conns[0] = BecomeServer(eport);
  486.  
  487. /* Read in the pixmaps file */
  488.   sprintf(filename,"%s/esrv_xpm.eric",LIBDIR);
  489.   infile = xfopen(filename,"r");
  490.   databuf = 0;
  491.   end = 0;
  492.   while(1) {
  493.     readbufline(buf,500,infile);
  494.     if (*buf == '\0')
  495.       break;
  496.     if(strncmp(buf,"ESRV_XPM ",9)!=0 ||
  497.        buf[14] != ' ') {
  498.       fprintf(stderr,"whoa, bad esrv_xpm line; not ESRV_XPM ...\n%s",buf);
  499.       abort();
  500.     }
  501.     num = atoi(buf+9);
  502.     if (num<0 || num>=MAXFACENUM) {
  503.       fprintf(stderr,"whoa, pixmap num %d \\not\\in 0..%d\n%s",
  504.           num,MAXFACENUM,buf);
  505.       abort();
  506.     }
  507.     buf[strlen(buf)-1] = '\0';
  508.     if (faces[num].name != NULL) {
  509.       fprintf(stderr,"whoa, pixmap #%d duplicated??\n",num);
  510.       abort();
  511.     }
  512.     faces[num].name = xmalloc(strlen(buf+15)+1);
  513.     strcpy(faces[num].name,buf+15);
  514.     cur = databuf;
  515.     /* Collect all the data for this pixmap */
  516.     while(1) {
  517.       readbufline(buf,500,infile);
  518.       if (*buf == '\0') {
  519.     fprintf(stderr,"whoa, pixmap #%d not terminated??\n",num);
  520.     abort();
  521.       }
  522.       if (strcmp(buf,"ESRV_XPM_END\n")==0)
  523.     break;
  524.       len = strlen(buf);
  525.       if (cur+len > end) {
  526.     long tmp = cur - databuf;
  527.     long tmp2 = end - databuf;
  528.     databuf = xrealloc(databuf,tmp2+10000);
  529.     cur = databuf+tmp;
  530.     end = databuf+tmp2+10000;
  531.       }
  532.       strcpy(cur,buf);
  533.       cur += len;
  534.     }
  535.     /* Collected all the data, put it into the pixmap buffer */
  536.     faces[num].data = xmalloc(cur-databuf+1);
  537.     faces[num].datalen = cur-databuf+1;
  538.     memcpy(faces[num].data, databuf,cur-databuf);
  539.     faces[num].data[cur-databuf] = '\0';
  540.   }
  541.   xfclose(infile);
  542.   free(databuf);
  543.  
  544.   /* Assume bitmap information parallel to pixmap information */
  545.   sprintf(filename,"%s/%s.cfb",LIBDIR,FONTNAME);
  546.   if ((infile = open_and_uncompress(filename,0,&comp))==NULL) {
  547.     LOG(llevError,"Can't open %s file",filename);
  548.     abort();
  549.   }
  550.   for(num=0;num<MAXFACENUM;num++) {
  551.     if (faces[num].name == NULL)
  552.       break; /* Last one -- assumes pixmaps are contiguous. */
  553.     if (fread(faces[num].bitmapdata, 24 * 3, 1, infile) != 1) {
  554.       printf("Unable to read bitmap data for face #%d\n",num);
  555.       abort();
  556.     }
  557.   }
  558.   while(num<MAXFACENUM) {
  559.     if (faces[num].name != NULL) {
  560.       printf("Non-contiguous faces, %d sits in middle of nowhere.\n",num);
  561.       abort();
  562.     }
  563.     num++;
  564.   }
  565.   close_and_delete(infile, comp);
  566. #endif
  567. }
  568.  
  569. /* Either keep this near the start or end of the file so it is
  570.  * at least reasonablye easy to find.
  571.  */
  572.  
  573. #if ERICSERVER
  574. struct CmdMapping {
  575.   char *cmdname;
  576.   void (*cmdproc)(ArgList,int);
  577. };
  578.  
  579. static struct CmdMapping commands[] = {
  580.   { "version", VersionCmd },
  581.   { "addme", AddMeCmd },
  582.   { "keyconversion", KeyConversionCmd },
  583.   { "keypress", KeyPressCmd },
  584.   { "keyrelease", KeyReleaseCmd },
  585.   { "examine", ExamineCmd },
  586.   { "apply", ApplyCmd },
  587.   { "move", MoveCmd },
  588.   { "reply", ReplyCmd},
  589.   { "command", PlayerCmd},
  590. };
  591.  
  592.  
  593. #define NCOMMANDS (sizeof(commands)/sizeof(struct CmdMapping))
  594.  
  595. static void HandleClient(int cnum)
  596. {
  597.   TcpSocket conn = conns[cnum];
  598.   ArgList msg;
  599.   int i;
  600.   char *cmd;
  601.  
  602.   msg = ArgList_receive(conn);
  603.   if (ArgList_getLong(msg,0)!= STRINGCOMMAND) {
  604.     printf("Bad message from client (%ld)\n",ArgList_getLong(msg,0));
  605.     exit(1);
  606.   }
  607.   cmd = ArgList_getString(msg,1);
  608.   for(i=0;i < NCOMMANDS;i++) {
  609.     if (strcmp(cmd,commands[i].cmdname)==0) {
  610.       commands[i].cmdproc(msg,cnum);
  611.       break;
  612.     }
  613.   }
  614.   if (i == NCOMMANDS) {
  615.     printf("Bad command from client (%s)\n",cmd);
  616.   }
  617.   ArgList_destroy(msg);
  618. }
  619. #endif
  620.  
  621. void esrv_quit_player();
  622. void doeric_server()
  623. {
  624. #if ERICSERVER
  625.   volatile int i;
  626.   long cid;
  627.  
  628.   for(i=1;i<nconns;i++) {
  629.     if (cinfo[i].state == CState_Dead) {
  630.       cid = cinfo[i].client_id;
  631.       dropconnection(i);
  632.       esrv_quit_player(cid);
  633.       i--;
  634.     }
  635.   }
  636.      WaitForInput(conns,nconns,0);
  637.     if (HasInput(conns[0])) {
  638.         printf("New Connection\n");
  639.         conns = xrealloc(conns,sizeof(TcpSocket)*(nconns+1));
  640.         cinfo = xrealloc(cinfo,sizeof(ClientInfo)*(nconns+1));
  641.         conns[nconns] = AcceptConnection(conns[0],NULL);
  642.         nconns++;
  643.         InitConnection(nconns-1);
  644.     }
  645.     for(i=1;i<nconns;i++) {
  646.         if (HasInput(conns[i])) {
  647.         WITH_HANDLING {
  648.             HandleClient(i);
  649.         } HANDLE {
  650.             BEGIN_MATCH
  651.             XMATCH(tcplib,NothingRead) {
  652.             } XMATCH(tcplib,ReadError) {
  653.             } XMATCH(tcplib,WriteFailed) {
  654.             } END_MATCH;
  655.             cid = cinfo[i].client_id;
  656.             dropconnection(i);
  657.             esrv_quit_player(cid);
  658.             i--;
  659.         } END_HANDLING;
  660.         }
  661.     }
  662. #endif
  663. }
  664.  
  665. int ericfd()
  666. {
  667. #if ERICSERVER
  668.   printf("Called ericfd()\n");
  669.   return GetTcpSocketFD(conns[0]);
  670. #else
  671.   return 0;
  672. #endif
  673. }
  674.  
  675. void esrv_remove_player(long client_id)
  676. {
  677. #if ERICSERVER
  678.   int i;
  679.   
  680.   for(i=0;i<nconns;i++) {
  681.     if (cinfo[i].client_id == client_id) {
  682.       cinfo[i].state = CState_Dead;
  683.       break;
  684.     }
  685.   }
  686. #endif
  687. }
  688.  
  689. void esrv_drawinfo(long client_id,const char *str)
  690. {
  691. #if ERICSERVER
  692.   int cnum;
  693.   ArgList msg;
  694.  
  695.   if ((cnum = getcnum(client_id))<0) {
  696.     fprintf(logfile,"client %ld is gone.\n",client_id);
  697.     return;
  698.   }
  699.   msg = ArgList_create();
  700.   ArgList_addLong(msg,STRINGCOMMAND);
  701.   ArgList_addString(msg,"drawinfo");
  702.   ArgList_addChar(msg,NDI_BLACK);
  703.   ArgList_addString(msg,(char*)str);
  704.   SWH(cnum,msg);
  705.   ArgList_destroy(msg);
  706. #endif
  707. }
  708.  
  709.  
  710. void send_query(long client_id, uint8 flags, char *text)
  711. {
  712. #if ERICSERVER
  713.   int cnum;
  714.   ArgList msg;
  715.  
  716.   if ((cnum = getcnum(client_id))<0) {
  717.     fprintf(logfile,"client %ld is gone.\n",client_id);
  718.     return;
  719.   }
  720.  
  721.   msg = ArgList_create();
  722.   ArgList_addLong(msg,STRINGCOMMAND);
  723.   ArgList_addString(msg,"query");
  724.   ArgList_addChar(msg, flags);
  725.   ArgList_addString(msg,text);
  726.   SWH(cnum,msg);
  727.   ArgList_destroy(msg);
  728. #endif
  729. }
  730.  
  731.  
  732. void esrv_print_msg(long client_id,int color, char *str)
  733. {
  734. #if ERICSERVER
  735.   int cnum;
  736.   ArgList msg;
  737.  
  738.   if ((cnum = getcnum(client_id))<0) {
  739.     fprintf(logfile,"client %ld is gone.\n",client_id);
  740.     return;
  741.   }
  742.   msg = ArgList_create();
  743.   ArgList_addLong(msg,STRINGCOMMAND);
  744.   ArgList_addString(msg,"drawinfo");
  745.   ArgList_addChar(msg,color);
  746.   ArgList_addString(msg,str);
  747.   SWH(cnum,msg);
  748.   ArgList_destroy(msg);
  749. #endif
  750. }
  751.  
  752. void esrv_write_ch(long client_id,unsigned char key)
  753. {
  754. #if ERICSERVER
  755.  
  756. #if 1    /* With the new input handling, this should not happen */
  757.   fprintf(stderr,"esrv_write_ch called\n");
  758.   return;
  759. #else
  760.   int cnum;
  761.   ArgList msg;
  762.  
  763.   if ((cnum = getcnum(client_id))<0) {
  764.     fprintf(logfile,"client %ld is gone.\n",client_id);
  765.     return;
  766.   }
  767.   msg = ArgList_create();
  768.   ArgList_addLong(msg,STRINGCOMMAND);
  769.   ArgList_addString(msg,"write_ch");
  770.   ArgList_addLong(msg,key);
  771.   SWH(cnum,msg);
  772.   ArgList_destroy(msg);
  773. #endif
  774. #endif
  775. }
  776.  
  777. void esrv_foo(long client_id,char *foo)
  778. {
  779. #if ERICSERVER
  780.   int cnum;
  781.   ArgList msg;
  782.  
  783.   if ((cnum = getcnum(client_id))<0) {
  784.     fprintf(logfile,"client %ld is gone.\n",client_id);
  785.     return;
  786.   }
  787.   msg = ArgList_create();
  788.   ArgList_addLong(msg,STRINGCOMMAND);
  789.   ArgList_addString(msg,"foo");
  790.   ArgList_addString(msg,foo);
  791.   /*SWH(cnum,msg);*/
  792.   ArgList_destroy(msg);
  793. #endif
  794. }
  795.  
  796. void esrv_bar(long client_id,char *foo)
  797. {
  798. #if ERICSERVER
  799.   int cnum;
  800.   ArgList msg;
  801.  
  802.   if ((cnum = getcnum(client_id))<0) {
  803.     fprintf(logfile,"client %ld is gone.\n",client_id);
  804.     return;
  805.   }
  806.   msg = ArgList_create();
  807.   ArgList_addLong(msg,STRINGCOMMAND);
  808.   ArgList_addString(msg,"bar");
  809.   ArgList_addString(msg,foo);
  810.   /*SWH(cnum,msg);*/
  811.   ArgList_destroy(msg);
  812. #endif
  813. }
  814.  
  815. /* Sends the stats to the client - only sends them if they have changed */
  816.  
  817. #define AddIfLong(Old,New,Type) if (Old != New) {\
  818.              Old = New; \
  819.              ArgList_addChar(msg,Type);\
  820.              ArgList_addLong(msg,New);\
  821.                }
  822. #define AddIfFloat(Old,New,Type) if (Old != New) {\
  823.              Old = New; \
  824.              ArgList_addChar(msg,Type);\
  825.              ArgList_addLong(msg,(long)(New*FLOAT_MULTI));\
  826.             }
  827. #define AddIfString(Old,New,Type) if (Old == NULL || strcmp(Old,New)) {\
  828.                if (Old) free(Old);\
  829.                        Old = strdup_local(New);\
  830.                ArgList_addChar(msg,Type);\
  831.                ArgList_addString(msg,New);\
  832.             }
  833. void esrv_update_stats(long client_id, object *pl)
  834. {
  835. #if ERICSERVER
  836.     int cnum;
  837.     ArgList msg;
  838.     char buf[MAX_BUF];
  839.  
  840.     if ((cnum = getcnum(client_id))<0) {
  841.     fprintf(stderr,"update_stats to not there person?\n");
  842.     return;
  843.     }
  844.     msg = ArgList_create();
  845.     ArgList_addLong(msg,STRINGCOMMAND);
  846.     ArgList_addString(msg,"stats");
  847.  
  848.     AddIfLong(pl->contr->last_stats.hp, pl->stats.hp, CS_STAT_HP);
  849.     AddIfLong(pl->contr->last_stats.maxhp, pl->stats.maxhp, CS_STAT_MAXHP);
  850.     AddIfLong(pl->contr->last_stats.sp, pl->stats.sp, CS_STAT_SP);
  851.     AddIfLong(pl->contr->last_stats.maxsp, pl->stats.maxsp, CS_STAT_MAXSP);
  852.     AddIfLong(pl->contr->last_stats.grace, pl->stats.grace, CS_STAT_GRACE);
  853.     AddIfLong(pl->contr->last_stats.maxgrace, pl->stats.maxgrace, CS_STAT_MAXGRACE);
  854.     AddIfLong(pl->contr->last_stats.Str, pl->stats.Str, CS_STAT_STR);
  855.     AddIfLong(pl->contr->last_stats.Int, pl->stats.Int, CS_STAT_INT);
  856. /* added this to allow Pow stat - b.t. */
  857.     AddIfLong(pl->contr->last_stats.Pow, pl->stats.Pow, CS_STAT_POW);
  858.     AddIfLong(pl->contr->last_stats.Wis, pl->stats.Wis, CS_STAT_WIS);
  859.     AddIfLong(pl->contr->last_stats.Dex, pl->stats.Dex, CS_STAT_DEX);
  860.     AddIfLong(pl->contr->last_stats.Con, pl->stats.Con, CS_STAT_CON);
  861.     AddIfLong(pl->contr->last_stats.Cha, pl->stats.Cha, CS_STAT_CHA);
  862.     AddIfLong(pl->contr->last_stats.exp, pl->stats.exp, CS_STAT_EXP);
  863.     AddIfLong(pl->contr->last_level, pl->level, CS_STAT_LEVEL);
  864.     AddIfLong(pl->contr->last_stats.wc, pl->stats.wc, CS_STAT_WC);
  865.     AddIfLong(pl->contr->last_stats.ac, pl->stats.ac, CS_STAT_AC);
  866.     AddIfLong(pl->contr->last_stats.dam, pl->stats.dam, CS_STAT_DAM);
  867.     AddIfLong(pl->contr->last_armour, pl->armour, CS_STAT_ARMOUR);
  868.     AddIfFloat(pl->contr->last_speed, pl->speed, CS_STAT_SPEED);
  869.     AddIfLong(pl->contr->last_stats.food, pl->stats.food, CS_STAT_FOOD);
  870.     AddIfFloat(pl->contr->last_weapon_sp, pl->contr->weapon_sp, CS_STAT_WEAP_SP);
  871.  
  872.     rangetostring(pl, buf);
  873.     AddIfString(cinfo[cnum].stats.range, buf, CS_STAT_RANGE);
  874.     set_title(pl, buf);
  875.     AddIfString(cinfo[cnum].stats.title, buf, CS_STAT_TITLE);
  876.  
  877.     if (ArgList_getLength(msg)>2) { 
  878.     /* always has size 2 for stringcmd, "stats" */
  879.     printf("stats len %d\n",ArgList_getLength(msg));
  880.     SWH(cnum,msg);
  881.     }
  882.     ArgList_destroy(msg);
  883. #endif
  884. }
  885.  
  886.  
  887.  
  888.  
  889. #if ERICSERVER
  890. /*
  891.  *  These are used to encode to simple commands, no need 
  892.  *  all overhead to ArfList handling
  893.  *
  894.  *  Made cmd_buf to HUGE_BUF - this is needed for players that have a lot
  895.  * of stuff in their inventory (using MAX_BUF gets overflowed)
  896.  */
  897. static char cmd_buf[HUGE_BUF], *buf_ptr;
  898.  
  899. #define ADD_LONG(p,l) (*(p)++ = ((unsigned long)l) >> 24 & 0xFF,\
  900.         *(p)++ = ((unsigned long)l) >> 16 & 0xFF,\
  901.         *(p)++ = ((unsigned long)l) >> 8 & 0xFF,\
  902.         *(p)++ = ((unsigned long)l) & 0xFF)
  903.  
  904. #define ADD_STRING(p,s) (strcpy (p,s), p+=strlen(p)+1)
  905.  
  906. void esrv_send_simple_cmd(long client_id, char *cmd)
  907. {
  908.     ArgList msg;
  909.     int cnum;
  910.  
  911.     if ((cnum = getcnum(client_id))<0) {
  912.     fprintf(logfile,"client %ld is gone.\n",client_id);
  913.     return;
  914.     }
  915.     msg = ArgList_create();
  916.     ArgList_addLong(msg,STRINGCOMMAND);
  917.     ArgList_addString(msg, cmd);
  918.     ArgList_addBuf(msg, cmd_buf, buf_ptr - cmd_buf);
  919.     SWH(cnum,msg);
  920.     ArgList_destroy(msg);
  921. }
  922. #endif
  923.  
  924. void esrv_new_player(long client_id, long tag, char *name, long weight, 
  925.     long face)
  926. {
  927. #if ERICSERVER
  928.     buf_ptr = cmd_buf;
  929.     ADD_LONG (buf_ptr, tag);
  930.     ADD_LONG (buf_ptr, weight);
  931.     ADD_LONG (buf_ptr, face);
  932.     ADD_STRING (buf_ptr, name);
  933.     esrv_send_simple_cmd (client_id, "player");
  934.   #endif
  935. }
  936.  
  937. /*
  938.  *  The next 3 functions must be called in the following order: 
  939.  *
  940.  *  esrv_new_location()  starts making new item list
  941.  *  esrv_add_item()      adds new item to that list 
  942.  *  esrv_send_items()   sends the item list to the client
  943.  */
  944. void esrv_new_location (long loc)
  945. {
  946. #if ERICSERVER
  947.     buf_ptr = cmd_buf;
  948.     ADD_LONG (buf_ptr, loc);
  949. #endif
  950. }
  951.  
  952. void esrv_add_item (long client_id, long tag, long flags, long weight, 
  953.     long face, char *name)
  954. {
  955. #if ERICSERVER
  956.     int cnum;
  957.  
  958.     if ((cnum = getcnum(client_id))<0) {
  959.     fprintf(logfile,"client %ld is gone.\n",client_id);
  960.     return;
  961.     }
  962.     if (! cinfo[cnum].faces_sent[face])
  963.       esrv_send_face(client_id, face);
  964.  
  965.     ADD_LONG (buf_ptr, tag);
  966.     ADD_LONG (buf_ptr, flags);
  967.     ADD_LONG (buf_ptr, weight);
  968.     ADD_LONG (buf_ptr, face);
  969.     ADD_STRING (buf_ptr, name);
  970. #endif
  971. }
  972.  
  973. #if 0
  974. void esrv_send_item(long client_id, long tag, long loc, char *name, 
  975.     long weight, long face, long flags)
  976. {
  977. #if ERICSERVER
  978.     esrv_new_location (loc);
  979.     esrv_add_item (client_id, tag, flags, weight, face, name);
  980.     esrv_send_simple_cmd (client_id, "item");
  981. #endif
  982. }
  983. #endif
  984.  
  985. void esrv_del_item(long client_id, long tag)
  986. {
  987. #if ERICSERVER
  988.     buf_ptr = cmd_buf;
  989.     ADD_LONG (buf_ptr, -1);
  990.     ADD_LONG (buf_ptr, tag);
  991.     esrv_send_simple_cmd (client_id, "item");
  992. #endif
  993. }
  994.  
  995.  
  996. /* All the funky map routines */
  997. #if ERICSERVER
  998. static long map_client = -1;
  999. static int map_cnum;
  1000. static struct Map newmap;
  1001. #endif
  1002. void esrv_send_face(long client_id,short face_num)
  1003. {
  1004. #if ERICSERVER
  1005.   int cnum;
  1006.   ArgList msg;
  1007.  
  1008.   if ((cnum = getcnum(client_id))<0) {
  1009.     fprintf(stderr,"send_face to not there person?\n");
  1010.     return;
  1011.   }
  1012.   if (face_num < 0 || face_num >= MAXFACENUM) {
  1013.     fprintf(stderr,"esrv_send_face(,%d) out of bounds??\n",face_num);
  1014.     abort();
  1015.   }
  1016.   if (faces[face_num].data == NULL) {
  1017.     fprintf(stderr,"faces[%d].data == NULL\n",face_num);
  1018.     abort();
  1019.   }
  1020.   
  1021.   if (cinfo[cnum].facesendmode == Send_Face_Pixmap) {
  1022.     msg = ArgList_create();
  1023.     ArgList_addLong(msg,STRINGCOMMAND);
  1024.     ArgList_addString(msg,"pixmap");
  1025.     ArgList_addLong(msg,face_num);
  1026.     ArgList_addBuf(msg,faces[face_num].data,faces[face_num].datalen);
  1027.     SWH(cnum,msg);
  1028.     ArgList_destroy(msg);
  1029.   } else if (cinfo[cnum].facesendmode == Send_Face_Bitmap) {
  1030.   } else if (cinfo[cnum].facesendmode == Send_Face_None) {
  1031.   } else {
  1032.     fprintf(stderr,"Invalid face send mode on cnum #%d\n",cnum);
  1033.     abort();
  1034.   }
  1035. /*  printf("send_pixmap %d to %ld\n",face_num,client_id);*/
  1036.   cinfo[cnum].faces_sent[face_num] = 1;
  1037. #endif
  1038. }
  1039.  
  1040. void esrv_map_new(long client_id)
  1041. {
  1042. #if ERICSERVER
  1043.   if (map_client != -1) {
  1044.     fprintf(stderr,"bad code -- didn't finish updating map\n");
  1045.     return;
  1046.   }
  1047.   map_client = client_id;
  1048.   map_cnum = getcnum(client_id);
  1049.   memset(&newmap,0,sizeof(struct Map));
  1050. #endif
  1051. /*  printf("NewMap for %ld\n",client_id);*/
  1052. }
  1053.  
  1054. void esrv_map_clearcell(long client_id,int x,int y)
  1055. {
  1056. #if ERICSERVER
  1057.   if (client_id != map_client) {
  1058.     fprintf(stderr,"bad user -- switched clientbeing updated\n");
  1059.     abort();
  1060.   }
  1061.   if (x<0||x>10 ||y<0 ||y>10) {
  1062.     fprintf(stderr,"bad user x/y not in 0..10\n");
  1063.     abort();
  1064.   }
  1065.   newmap.cells[x][y].count = 0;
  1066. /*  printf("ClearCell on %ld:(%d,%d)\n",client_id,x,y);*/
  1067. #endif
  1068. }
  1069.  
  1070. void esrv_map_setbelow(long client_id,int x,int y,short face_num)
  1071. {
  1072. #if ERICSERVER
  1073.   if (client_id != map_client) {
  1074.     fprintf(stderr,"bad user -- switched clientbeing updated\n");
  1075.     abort();
  1076.   }
  1077.   if (x<0||x>10 ||y<0 ||y>10 || face_num < 0 || face_num > MAXFACENUM) {
  1078.     fprintf(stderr,"bad user x/y/facenum not in 0..10,0..10,0..%d\n",
  1079.         MAXFACENUM-1);
  1080.     abort();
  1081.   }
  1082.   if(newmap.cells[x][y].count >= MAXMAPCELLFACES) {
  1083.     fprintf(stderr,"whoa, too many faces\n");
  1084.     abort();
  1085.   }
  1086.   newmap.cells[x][y].faces[newmap.cells[x][y].count] = face_num;
  1087.   newmap.cells[x][y].count ++;
  1088.   if (map_cnum>0 && cinfo[map_cnum].faces_sent[face_num] == 0)
  1089.     esrv_send_face(client_id,face_num);
  1090.       
  1091. /*  printf("SetBelow on %ld:(%d,%d; %d)\n",client_id,x,y,face_num);*/
  1092. #endif
  1093. }
  1094.  
  1095. struct LayerCell {
  1096.   char xy;
  1097.   short face;
  1098. };
  1099.  
  1100. struct MapLayer {
  1101.   int count;
  1102.   struct LayerCell lcells[121];
  1103. };
  1104.  
  1105. #if ERICSERVER
  1106. int mapcellchanged(int cnum,int i,int j)
  1107. {
  1108.   int k;
  1109.  
  1110.   if (cinfo[cnum].lastmap.cells[i][j].count != newmap.cells[i][j].count)
  1111.     return 1;
  1112.   for(k=0;k<newmap.cells[i][j].count;k++) {
  1113.     if (cinfo[cnum].lastmap.cells[i][j].faces[k] !=
  1114.     newmap.cells[i][j].faces[k]) {
  1115.       return 1;
  1116.     }
  1117.   }
  1118.   return 0;
  1119. }
  1120.   
  1121. unsigned char *compactlayer(int cnum,unsigned char *cur)
  1122. {
  1123.   int i,j,k;
  1124.   int face;
  1125.   unsigned char *fcur;
  1126.   struct MapLayer layers[MAXMAPCELLFACES];
  1127.   
  1128.   for(k = 0;k<MAXMAPCELLFACES;k++)
  1129.     layers[k].count = 0;
  1130.   fcur = cur;
  1131.   for(i=0;i<11;i++) {
  1132.     for(j=0;j<11;j++) {
  1133.       if (!mapcellchanged(cnum,i,j))
  1134.     continue;
  1135.       if (newmap.cells[i][j].count == 0) {
  1136.     *cur = i*11+j;
  1137.     cur++;
  1138.     continue;
  1139.       }
  1140.       for(k=0;k<newmap.cells[i][j].count;k++) {
  1141.     layers[k].lcells[layers[k].count].xy = i*11+j;
  1142.     layers[k].lcells[layers[k].count].face = 
  1143.       newmap.cells[i][j].faces[k];
  1144.     layers[k].count++;
  1145.       }
  1146.     }
  1147.   }
  1148.   if (fcur == cur && layers[0].count == 0)
  1149.     return cur;
  1150.   *cur = 255; /* mark end of explicitly cleared cells */
  1151.   cur++;
  1152.   for(k=0;k<MAXMAPCELLFACES;k++) {
  1153.     if (layers[k].count == 0)
  1154.       break; /* once a layer is entirely empty, no layer below it can
  1155.         have anything in it either */
  1156.     for(i=0;i<layers[k].count;) {
  1157.       fcur = cur;
  1158.       *cur = layers[k].lcells[i].face >> 8;
  1159.       cur++;
  1160.       *cur = layers[k].lcells[i].face & 0xFF;
  1161.       cur++;
  1162.       face = layers[k].lcells[i].face;
  1163.       for(j=i;j<layers[k].count;j++) {
  1164.     if (layers[k].lcells[j].face == face) {
  1165.       *cur = layers[k].lcells[j].xy;
  1166.       cur++;
  1167.       layers[k].lcells[j].face = -1;
  1168.     }
  1169.       }
  1170.       *(cur-1) = *(cur-1) | 128; /* mark for end of xy's; 11*11 < 128 */
  1171.       while(i < layers[k].count &&
  1172.         layers[k].lcells[i].face == -1)
  1173.     i++;
  1174.     }
  1175.     *fcur = *fcur | 128; /* mark for end of faces at this layer */
  1176.   }
  1177.   return cur;
  1178. }
  1179.  
  1180. unsigned char *compactstack(int cnum,unsigned char *cur)
  1181. {
  1182.   int i,j,k;
  1183.  
  1184.   for(i=0;i<11;i++) {
  1185.     for(j=0;j<11;j++) {
  1186.       if (!mapcellchanged(cnum,i,j))
  1187.     continue;
  1188.       /* Pack in the x/y */
  1189.       *cur = (i<<4)|j;
  1190.       cur++;
  1191.       /* Pack in a count */
  1192.       *cur = (newmap.cells[i][j].count)&0xFF;
  1193.       cur++;
  1194.       for(k=0;k<newmap.cells[i][j].count;k++) {
  1195.     *cur = (newmap.cells[i][j].faces[k] >> 8) & 0xFF;
  1196.     cur++;
  1197.     *cur = (newmap.cells[i][j].faces[k] & 0xFF);
  1198.     cur++;
  1199.       }
  1200.     }
  1201.   }
  1202.   return cur;
  1203. }
  1204.  
  1205. #endif /* #if ERICSERVER */
  1206.  
  1207. void esrv_map_doneredraw(long client_id)
  1208. {
  1209. #if ERICSERVER
  1210.   static long frames,bytes,tbytes,tframes;
  1211.   int cnum;
  1212.   unsigned char obuf[40000],*cur;
  1213.  
  1214.   ArgList msg;
  1215.  
  1216.   if (client_id != map_client) {
  1217.     fprintf(stderr,"bad user -- switched clientbeing updated\n");
  1218.     abort();
  1219.   }
  1220.   if ((cnum = getcnum(client_id))<0) {
  1221.     fprintf(stderr,"whoa, updating map for non-existant client\n");
  1222.     return;
  1223.   }
  1224.  
  1225. #if 1
  1226.   cur = compactlayer(cnum,obuf);
  1227. #else
  1228.   cur = compactstack(cnum,obuf);
  1229. #endif
  1230.   if (cur>obuf || cinfo[cnum].sentscroll) {
  1231.     if (tframes>100) {
  1232.       tframes = tbytes = 0;
  1233.     }
  1234.     tframes++;
  1235.     frames++;
  1236.     tbytes += (cur-obuf);
  1237.     bytes += (cur-obuf);
  1238. #if 0      
  1239.     printf("ts%d,a%d;lf%ld,la%d\n",
  1240.        cur-obuf,(int)((double)bytes/(double)frames +0.5),
  1241.        tframes,(int)((double)tbytes/(double)tframes + 0.5));
  1242. #endif
  1243.     memcpy(&cinfo[cnum].lastmap,&newmap,sizeof(struct Map));
  1244.     msg = ArgList_create();
  1245.     ArgList_addLong(msg,STRINGCOMMAND);
  1246.     ArgList_addString(msg,"map");
  1247.     ArgList_addBuf(msg,obuf,cur-obuf);
  1248.     SWH(cnum,msg);
  1249.     ArgList_destroy(msg);
  1250.     cinfo[cnum].sentscroll = 0;
  1251.   }
  1252.   map_client = -1;
  1253. #endif
  1254. }
  1255.  
  1256. void esrv_map_scroll(long client_id,int dx,int dy)
  1257. {
  1258. #if ERICSERVER
  1259.   int cnum;
  1260.   ArgList msg;
  1261.   struct Map newmap;
  1262.   int x,y;
  1263.  
  1264.   if ((cnum = getcnum(client_id))<0) {
  1265.     fprintf(stderr,"whoa, updating map for non-existant client\n");
  1266.     return;
  1267.   }
  1268.   msg = ArgList_create();
  1269.   ArgList_addLong(msg,STRINGCOMMAND);
  1270.   ArgList_addString(msg,"map_scroll");
  1271.   ArgList_addLong(msg,dx);
  1272.   ArgList_addLong(msg,dy);
  1273.   SWH(cnum,msg);
  1274.   ArgList_destroy(msg);
  1275.   /* the x and y here are coordinates for the new map, i.e. if we moved
  1276.      (dx,dy), newmap[x][y] = oldmap[x-dx][y-dy] */
  1277.   for(x=0;x<11;x++) {
  1278.     for(y=0;y<11;y++) {
  1279.       newmap.cells[x][y].count = 0;
  1280.       if (x+dx < 0 || x+dx >= 11)
  1281.     continue;
  1282.       if (y+dy < 0 || y+dy >= 11)
  1283.     continue;
  1284.       memcpy(&(newmap.cells[x][y]),
  1285.         &(cinfo[cnum].lastmap.cells[x+dx][y+dy]),sizeof(struct MapCell));
  1286.     }
  1287.   }
  1288.   memcpy(&(cinfo[cnum].lastmap), &newmap,sizeof(struct Map));
  1289.   cinfo[cnum].sentscroll = 1;
  1290. #endif
  1291. }
  1292.  
  1293.